home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Plus 2000 #5
/
Amiga Plus CD - 2000 - No. 5.iso
/
Tools
/
Dev
/
FPSE_src
/
hw.c
< prev
next >
Wrap
C/C++ Source or Header
|
2000-01-01
|
22KB
|
814 lines
/*
Hardware addressing
===================
Written by LDChen
Modified by LDChen
*/
#include "fpse.h"
#ifdef MSB_FIRST
#define HW8(a) hwarea[4*((a)/4)+3-(a)%4]
#define HW16(a) (*(UINT16*)&hwarea[4*((a)/4)+2-(a)%4])
#define HW32(a) (*(UINT32*)&hwarea[a])
#else
#define HW8(a) hwarea[a]
#define HW16(a) (*(UINT16*)&hwarea[a])
#define HW32(a) (*(UINT32*)&hwarea[a])
#endif
#define NOPRINTPC 1
typedef struct {
UINT32 addr;
char *name;
} NAM;
/*
1f801000
1f801004
1f801008
1f80100c
1f801010
1f80101c
1f802041 ???
*/
static NAM hwnames[] = {
{0x1f801014,"spu_delay"},
{0x1f801018,"dv5_delay"},
{0x1f801020,"com_delay"},
{0x1f801040,"sio0_data"},
{0x1f801044,"sio0_status"},
{0x1f801048,"sio0_mode"},
{0x1f80104a,"sio0_control"},
{0x1f80104e,"sio0_baud"},
{0x1f801050,"sio1_data"},
{0x1f801054,"sio1_status"},
{0x1F801058,"sio1_mode"},
{0x1f80105a,"sio1_control"},
{0x1f80105e,"sio1_baud"},
{0x1f801060,"ram_size"},
{0x1f801070,"int_reg"},
{0x1f801074,"int_mask"},
{0x1f801080,"mdec_dma0_madr"},
{0x1f801084,"mdec_dma0_bcr"},
{0x1f801088,"mdec_dma0_chcr"},
{0x1f801090,"mdec_dma1_madr"},
{0x1f801094,"mdec_dma1_bcr"},
{0x1f801098,"mdec_dma1_chcr"},
{0x1f8010a0,"gpu_dma_madr"},
{0x1f8010a4,"gpu_dma_bcr"},
{0x1f8010a8,"gpu_dma_chcr"},
{0x1f8010b0,"cd_dma_madr"},
{0x1f8010b4,"cd_dma_bcr"},
{0x1f8010b8,"cd_dma_chcr"},
{0x1f8010c0,"spu_dma_madr"},
{0x1f8010c4,"spu_dma_bcr"},
{0x1f8010c8,"spu_dma_chcr"},
{0x1f8010d0,"dma5_madr"},
{0x1f8010d4,"dma5_bcr"},
{0x1f8010d8,"dma5_chcr"},
{0x1f8010e0,"dma6_madr"},
{0x1f8010e4,"dma6_bcr"},
{0x1f8010e8,"dma6_chcr"},
{0x1f8010f0,"dma_pcr"},
{0x1f8010f4,"dma_icr"},
{0x1f801100,"t0_count"},
{0x1f801104,"t0_mode"},
{0x1f801108,"t0_target"},
{0x1f801110,"t1_count"},
{0x1f801114,"t1_mode"},
{0x1f801118,"t1_target"},
{0x1f801120,"t2_count"},
{0x1f801124,"t2_mode"},
{0x1f801128,"t2_target"},
{0x1f801800,"cdrom_reg0"},
{0x1f801801,"cdrom_reg1"},
{0x1f801802,"cdrom_reg2"},
{0x1f801803,"cdrom_reg3"},
{0x1f801810,"gpu_reg0"},
{0x1f801814,"gpu_reg1"},
{0x1f801820,"mdec_reg0"},
{0x1f801824,"mdec_reg1"},
{0x1f801d80,"spu_mvol_l"},
{0x1f801d82,"spu_mvol_r"},
{0x1f801d84,"spu_reverb_l"},
{0x1f801d86,"spu_reverb_r"},
{0x1f801d88,"spu_key_on_1"},
{0x1f801d8a,"spu_key_on_2"},
{0x1f801d8c,"spu_key_off_1"},
{0x1f801d8e,"spu_key_off_2"},
{0x1f801d90,"spu_key_modefm_1"},
{0x1f801d92,"spu_key_modefm_2"},
{0x1f801d94,"spu_key_modenoise_2"},
{0x1f801d96,"spu_key_modenoise_2"},
{0x1f801d98,"spu_key_modereverb_1"},
{0x1f801d9a,"spu_key_modereverb_2"},
{0x1f801d9c,"spu_key_channelactive_1"},
{0x1f801d9e,"spu_key_channelactive_2"},
{0x1f801da6,"spu_sbaddr"},
{0x1f801da8,"spu_data"},
{0x1f801daa,"spu_reg0"},
{0x1f801dac,"spu_reg1"},
{0x1f801dae,"spu_status"},
{0x1f801db0,"spu_cdvol_l"},
{0x1f801db2,"spu_cdvol_r"},
{0x1f801db4,"spu_extvol_l"},
{0x1f801db6,"spu_extvol_r"},
{0x1f801dc0,"spu_reverbconfig"},
{0x1f801dfc,"spu_factor_l"},
{0x1f801dfe,"spu_factor_r"},
{0x1f802030,"int_2000"},
{0x1f802040,"dip_switches"},
/* extension */
{0x1f000000,"parrom_status"},
{0x1f000001,"parrom_type"},
{0x1f005555,"parrom_reg0"},
{0x1f002aaa,"parrom_reg1"},
{0x1f060000,"par_in"}, /* byte */
{0x1f060008,"par_out"}, /* byte */
{0x1f020010,"par_status"}, /* bit 0: 1= busy */
{0x1f020018,"par_switch"}, /* bit 0: 1= on */
{0,""}
};
static char *sregname[] = {
"vol_l","vol_r","freq","sbadr","ar","adsr2","adsrvol","repeat"
};
char* hwname(unsigned long addr)
{
NAM *p;
static char buf[16];
for(p=hwnames; p->addr && p->addr!=addr; p++) ;
if (p->addr) return p->name;
if (addr>=0x1f801c00 && addr<0x1f801c00+16*24) {
sprintf(buf,"voice%d_%s",(int)((addr-0x1f801c00)/16),sregname[(addr&15)/2]);
} else sprintf(buf,"%08x",(int)addr);
return buf;
}
#define spu_reg0 HW16(0x1daa)
#define t0_count HW16(0x1100)
#define t0_mode HW32(0x1104)
#define t0_target HW16(0x1108)
#define t1_count HW16(0x1110)
#define t1_mode HW32(0x1114)
#define t1_target HW16(0x1118)
#define t2_count HW16(0x1120)
#define t2_mode HW32(0x1124)
#define t2_target HW16(0x1128)
#define int_reg HW16(0x1070)
#define int_mask HW16(0x1074)
#define dma_pcr HW32(0x10f0)
#define dma_icr HW32(0x10f4)
UINT8 hwarea[0x8000];
/*
counter mode
base = 0x48
0x10 è±ÝÂ?
0x01 Q[gðLø
0x100 0=clock/8 1=clock
*/
#define INTERRUPT(no) reg |= (1<<no)
#define UPPER 0xFFFF
static UINT32 base_count;
static UINT32 base_count2;
static UINT32 t0_limit=UPPER;
static UINT32 t1_limit=UPPER;
static UINT32 t2_limit=UPPER;
int Irq_Pulse = 0;
INT32 VSync_Register = 0;
INT32 Event_Register = 0;
INT32 Event_List[16];
UINT32 Event_Mask[16];
int (*EventCallBack[16])();
int (*VSyncCallBack[16])();
#define MAINCLOCK 33868800L
#define PER 64
#define HSYNC (MAINCLOCK/15734)
#define VSYNC (MAINCLOCK/60)
#define ESYNC 13
static int treg=0;
static int dec1_count=HSYNC;
int update_hw(void)
{
int reg = 0;
int tmp;
base_count+=PER;
if (base_count>=VSYNC) {
base_count=0;
PRINTF("VSync\n");
win_update();
INTERRUPT(INT_VSync);
}
tmp = t0_count + ((t0_mode & 0x100)?PER:PER/8);
if (tmp>=t0_limit && t0_count<t0_limit) {
tmp = 0;
// printf("t0 == limit\n");
if (t0_mode & 0x50) INTERRUPT(INT_CNT0);
}
t0_count=tmp;
if ((t1_mode & 0x100)==0) {
tmp = t1_count + PER;
if (tmp>=t1_limit && t1_count<t1_limit) {
tmp = 0;
// printf("t1 == limit\n");
if (t1_mode & 0x50) INTERRUPT(INT_CNT1);
}
t1_count=tmp;
} else
if ((dec1_count-=PER) <= 0) {
if (++t1_count == t1_limit) {
t1_count = 0;
// printf("t1 == limit\n");
if (t1_mode & 0x50) INTERRUPT(INT_CNT1);
}
dec1_count = HSYNC;
}
if ((t2_mode & 1) == 0)
{
tmp = t2_count + ((t2_mode & 0x200)?PER/8:PER);
if (tmp>=t2_limit && t2_count<t2_limit) {
tmp = 0;
// printf("t2 == limit\n");
if (t2_mode & 0x50) INTERRUPT(INT_CNT2);
}
t2_count=tmp;
}
if (++base_count2>=ESYNC) {
base_count2=0;
if (VSync_Register < 0)
{
int v = 1;
// PRINTF("Entering VSYNC EVENT\n");
for (tmp=0;tmp<16;tmp++)
{
if ((VSync_Register & v) && --Event_List[tmp] <= 0)
{
PRINTF("Found %d^ ASync\n",tmp);
treg |= v;
VSync_Register ^= v;
if ( (VSyncCallBack[tmp]) )
{
if (!VSyncCallBack[tmp]()) treg &= ~v;
}
}
v <<= 1;
}
if ((VSync_Register & 0x7FFFFFFF) == 0)
VSync_Register = 0;
}
}
if (dma_icr&0x7f000000) { INTERRUPT(INT_DMA); }
if (Event_Register < 0)
{
int x,y;
//printf("Async event enabled: %08x\n",Event_Register);
for(x=0;x<16;x++)
{
y = Event_Mask[x];
//printf("Event_List[%d]=%d\n",x,Event_List[x]);
if ((Event_Register & y) && Event_List[x] <= 0)
{
treg |= y;
Event_Register &= ~y;
if ( (EventCallBack[x]) )
{
if (!EventCallBack[x]()) treg &= ~y;
}
}
}
if (!(Event_Register & 0x7FFFFFFF))
Event_Register = 0;
}
reg |= Irq_Pulse;
HW32(0x1070) |= reg;
Irq_Pulse = tmp = 0;
if ((HW32(0x1074) & HW32(0x1070)))
tmp = 1;
HW32(0x1070) |= treg;
if ( (treg) && (HW32(0x1074) & treg) )
tmp = 1;
treg=0;
return tmp;
}
int update_counter(void)
{
return update_hw();
}
/* OT clear */
void dma6_exec(UINT32 adr,UINT32 bcr,UINT32 chcr)
{
if (chcr!=0x11000002) {
PRINTF("dma6 unknown %x\n",(int)chcr);
return;
}
if (!bcr) return;
adr &= 0xFFFFFF;
CompileFlush(adr-bcr*4,adr);
while (--bcr) {
*(UINT32*)&ram[adr & 0x1FFFFF] = SWAP32((adr-4)&0xffffff);
adr-=4;
}
*(UINT32*)&ram[adr & 0x1FFFFF] = SWAP32(0xffffff);
}
int hw_init(void)
{
int x;
#if AUTOSPEED
time_t t1;
UINT32 clk1 = rdtsc();
t1 = clock() + CLOCKS_PER_SEC;
while (clock() < t1);
oldcnt = rdtsc();
cpuspeed = (oldcnt - clk1);
printf("CPU speed: %d MHz\n",(int)(cpuspeed/1000000));
vsync = cpuspeed / 60; // -> 550000
hsync = vsync / 250;
#endif
memset(hwarea,0,0x8000);
// Init event masks
for (x=0;x<16;x++) {
Event_Mask[x] = 1<<x;
EventCallBack[x] = NULL;
VSyncCallBack[x] = NULL;
}
// Start initialization
mdec_init();
if (sio_init() != FPSE_OK) return FPSE_ERR;
cd_initvar();
if (win_init() != FPSE_OK) return FPSE_ERR;
return FPSE_OK;
}
void hw_close(void)
{
win_term();
}
static UINT32 ParReply = 0x57;
UINT8 hw_romread(UINT32 adr)
{
int ret;
switch (adr) {
case 0x1F020018:
case 0x1F020010:
ret = 1; break;
case 0x1F060000:
if (ParReply & 0xF0) ret = ParReply;
else {
if (ParReply < 4) ret = extrom[3-ParReply];
else ret = 0;
ParReply++;
}
break;
default:
if (adr > 0x1F000000 &&
adr < 0x1F020000) ret = *(UINT32 *)&extrom[adr & 0x1FFFF];
else ret = 0xFFFFFFFF; // Out of address
break;
}
PRINTF("read rom extension %s,%02x\n",hwname(adr),ret);
return ret;
}
void hw_romwrite(UINT32 adr, UINT32 data)
{
PRINTF("write rom extension %s,%02x\n",hwname(adr),(int)data);
data &= 0xFF;
switch (adr) {
case 0x1F060008:
switch (data) {
case 0x52: ParReply = 0x42; break;
case 0x57: if (actionreplay) ParReply = 0x58;
else ParReply = 0x55;
break;
case 0x55:
case 0x58: ParReply = 0; break;
default: break;
}
break;
}
}
UINT8 hw_read8(UINT32 adr)
{
int ret;
switch(adr){
case 0x1f801040: ret = sio_readdata8(&Sio0); break;
case 0x1f801050: ret = sio_readdata8(&Sio1); break;
case 0x1f801800: ret = cd0_read(); break;
case 0x1f801801: ret = cd1_read(); break;
case 0x1f801802: ret = cd2_read(); break;
case 0x1f801803: ret = cd3_read(); break;
default:
ret = HW8(adr-0x1f800000); break;
}
#if NOPRINTPC
printpc();
#endif
PRINTF("read byte %s,%02x\n",hwname(adr),ret);
return ret;
}
UINT16 hw_read16(UINT32 adr)
{
int ret;
switch(adr){
case 0x1f801070:
if (Event_Register < 0)
{
int x,y;
// ret = Event_RootCount;
// Event_RootCount++;
for(x=0;x<16;x++)
{
y = Event_Mask[x];
if (Event_Register & y)
// if (ret >= Event_List[x])
if (--Event_List[x] <= 0)
{
treg |= y;
Event_Register &= ~y;
}
if (!(Event_Register & 0x7FFFFFFF))
Event_Register = 0;
}
}
ret= HW16(0x1070)|treg; break;
/* SIO0 - Controllers & MemCards */
case 0x1f801040: ret = sio_readdata16(&Sio0); break;
case 0x1f801044: ret = Sio0.Status; break;
case 0x1F801048: ret = Sio0.Mode; break;
case 0x1f80104a: ret = Sio0.Ctrl.Control16; break;
case 0x1f80104e: ret = Sio0.Baud; break;
/* SIO1 - Serial port */
case 0x1f801050: ret = sio_readdata16(&Sio1); break;
case 0x1f801054: ret = Sio1.Status; break;
case 0x1F801058: ret = Sio1.Mode; break;
case 0x1f80105a: ret = Sio1.Ctrl.Control16; break;
case 0x1f80105e: ret = Sio1.Baud; break;
/*
case 0x1f801daa:
case 0x1f801dae:
return HW16(adr-0x1f800000);
*/
default:
if (adr>=0x1f801c00 && adr<0x1f801e00)
ret = SPU_Read(adr);
else ret = HW16(adr & 0x7FFF);
break;
}
#if NOPRINTPC
printpc();
#endif
PRINTF("read short %s,%04x\n",hwname(adr),ret);
return ret;
}
UINT32 hw_read32(UINT32 adr)
{
UINT32 ret;
switch(adr) {
case 0x1f801810: ret = GP0_Read(); break;
case 0x1f801814: ret = GP1_Read(); break;
/* SIO0 */
case 0x1f801040: ret = sio_readdata32(&Sio0); break;
/* SIO1 */
case 0x1f801050: ret = sio_readdata32(&Sio1); break;
case 0x1f801070:
if (Event_Register < 0)
{
int x,y;
// ret = Event_RootCount;
// Event_RootCount++;
//printf("Async event enabled: %08x\n",Event_Register);
for(x=0;x<16;x++)
{
//printf("Event_List[%d]=%d\n",x,Event_List[x]);
y = Event_Mask[x];
if (Event_Register & y)
// if (ret >= Event_List[x])
if (--Event_List[x] <= 0)
{
treg |= y;
Event_Register &= ~y;
}
if (!(Event_Register & 0x7FFFFFFF))
Event_Register = 0;
}
}
ret= HW32(0x1070)|treg; break;
case 0x1f801820: ret = mdec0_read(); break;
case 0x1f801824: ret = mdec1_read(); break;
#if 0
case 0x1f801088:
case 0x1f801098:
case 0x1f8010a8:
case 0x1f8010b8:
case 0x1f8010c8:
case 0x1f8010d8:
case 0x1f8010e8:
// dma_chcr
// busyÅÈÈÁ½ç readÉ 0x01000000 ªÏíé ?
// ret = 0;
// break;
case 0x1f8010f4:
// dma status
// ret = 0;
// break;
#endif
default:
ret = HW32(adr-0x1f800000);
break;
}
#if NOPRINTPC
printpc();
#endif
PRINTF("read long %s,%08x\n",hwname(adr),(int)ret);
return ret;
}
void hw_write8(UINT32 adr,UINT32 data)
{
#if NOPRINTPC
printpc();
#endif
PRINTF("write byte %s,%02x\n",hwname(adr),(int)data);
switch(adr){
case 0x1f801040: sio_writedata8(&Sio0,data); break;
case 0x1f801050: sio_writedata8(&Sio1,data); break;
case 0x1f801800: cd0_write(data); break;
case 0x1f801801: cd1_write(data); break;
case 0x1f801802: cd2_write(data); break;
case 0x1f801803: cd3_write(data); break;
default:
HW8(adr-0x1f800000)=data;
break;
}
}
void hw_write16(UINT32 adr,UINT32 data)
{
#if NOPRINTPC
printpc();
#endif
PRINTF("write short %s,%04x\n",hwname(adr),(int)data);
switch(adr) {
case 0x1f801040: sio_writedata16(&Sio0,data); break;
case 0x1f801048: sio_mode_write(&Sio0,data); break;
case 0x1f80104a: sio_control_write(&Sio0,data); break;
case 0x1f80104e: sio_baud_write(&Sio0,data); break;
case 0x1f801050: sio_writedata16(&Sio1,data); break;
case 0x1f801058: sio_mode_write(&Sio1,data); break;
case 0x1f80105a: sio_control_write(&Sio1,data); break;
case 0x1f80105e: sio_baud_write(&Sio1,data); break;
case 0x1f801070:
/* interrupt clear? */
HW16(0x1070) &= (data & HW16(0x1074));
treg &= (data & HW16(0x1074));
break;
case 0x1F801104:
HW16(0x1104) = data;
if ((data & 0x08)==0 || !t0_target) t0_limit = UPPER;
else t0_limit = t0_target;
break;
case 0x1F801108:
HW16(0x1108) = data & 0xFFFF;
if ((t0_mode & 0x08)==0 || !t0_target) t0_limit = UPPER;
else t0_limit = t0_target;
break;
case 0x1F801114:
HW16(0x1114) = data;
if ((data & 0x08)==0 || !t1_target) t1_limit = UPPER;
else t1_limit = t1_target;
break;
case 0x1F801118:
HW16(0x1118) = data & 0xFFFF;
if ((t1_mode & 0x08)==0 || !t1_target) t1_limit = UPPER;
else t1_limit = t1_target;
break;
case 0x1F801124:
HW16(0x1124) = data;
if ((data & 0x08)==0 || !t2_target) t2_limit = UPPER;
else t2_limit = t2_target;
break;
case 0x1F801128:
HW16(0x1128) = data & 0xFFFF;
if ((t2_mode & 0x08)==0 || !t2_target) t2_limit = UPPER;
else t2_limit = t2_target;
break;
default:
if (adr>=0x1f801c00 && adr<0x1f801e00) {
SPU_Write(adr,data);
break;
}
HW16(adr-0x1f800000)=data;
break;
}
}
void hw_write32(UINT32 adr,UINT32 data)
{
#if NOPRINTPC
printpc();
#endif
PRINTF("write long %s,%08x\n",hwname(adr),(int)data);
switch(adr) {
case 0x1f801040: sio_writedata32(&Sio0,data); break;
case 0x1f801050: sio_writedata32(&Sio1,data); break;
case 0x1f801070:
/* ½ðXgAµÄà interrupt clear? */
HW32(0x1070) &= (data & HW32(0x1074));
treg &= (data & HW32(0x1074));
break;
case 0x1f801810: GP0_Write(data); return;
case 0x1f801814: GP1_Write(data); return;
#define DMA_ENABLE(n) (dma_pcr&(8<<(n*4)))
#define DMA_INTERRUPT(n) if (dma_icr&(1<<(16+n))) dma_icr |= 0x80000000|(1<<(24+n));
case 0x1f801088: /* MDECin */
if (DMA_ENABLE(0)) {
dma0_exec(HW32(0x1080),HW32(0x1084),data);
HW32(0x1088) = data&~0x01000000;
DMA_INTERRUPT(0);
}
break;
case 0x1f801098: /* MDECout */
if (DMA_ENABLE(1)) {
dma1_exec(HW32(0x1090),HW32(0x1094),data);
HW32(0x1098) = data&~0x01000000;
DMA_INTERRUPT(1);
}
break;
case 0x1f8010a8: /* GPU DMA */
if (DMA_ENABLE(2)) {
// printf("GPUDMA %08x %08x %08x\n",
// HW32(0x10a0),HW32(0x10a4),data);
GPU_DmaExec(HW32(0x10a0),HW32(0x10a4),data);
HW32(0x10A8) = data&~0x01000000;
DMA_INTERRUPT(2);
}
break;
case 0x1f8010b8: /* CDROM DMA */
if (DMA_ENABLE(3)) {
dma3_exec(HW32(0x10b0),HW32(0x10b4),data);
HW32(0x10B8) = data&~0x01000000;
DMA_INTERRUPT(3);
}
break;
case 0x1f8010c8: /* SPU DMA */
if (DMA_ENABLE(4)) {
SPU_DmaExec(HW32(0x10c0),HW32(0x10c4),data);
HW32(0x10C8) = data&~0x01000000;
DMA_INTERRUPT(4);
}
break;
#if 0
case 0x1f8010d8: /* PIO DMA */
if (DMA_ENABLE(5)) {
dma5_exec(HW32(0x10D0),HW32(0x10D4),data);
HW32(0x10D8) = data&~0x01000000;
DMA_INTERRUPT(5);
}
break;
#endif
case 0x1f8010e8: /* OT clear DMA */
if (DMA_ENABLE(6)) {
dma6_exec(HW32(0x10E0),HW32(0x10E4),data);
HW32(0x10E8) = data&~0x01000000;
DMA_INTERRUPT(6);
}
break;
case 0x1f8010f4:
HW32(0x10F4) = data & 0xFFFFFF;
break;
case 0x1F801104:
HW32(0x1104) = data;
if (data & 0x08) t0_limit = t0_target;
else t0_limit = 0xFFFF;
break;
case 0x1F801108:
HW32(0x1108) = data & 0xFFFF;
if (t0_mode & 0x08) t0_limit = t0_target;
else t0_limit = 0xFFFF;
break;
case 0x1F801114:
HW32(0x1114) = data;
if (data & 0x08) t1_limit = t1_target;
else t1_limit = 0xFFFF;
break;
case 0x1F801118:
HW32(0x1118) = data & 0xFFFF;
if (t1_mode & 0x08) t1_limit = t1_target;
else t1_limit = 0xFFFF;
break;
case 0x1F801124:
HW32(0x1124) = data;
if (data & 0x08) t2_limit = t2_target;
else t2_limit = 0xFFFF;
break;
case 0x1F801128:
HW32(0x1128) = data & 0xFFFF;
if (t2_mode & 0x08) t2_limit = t0_target;
else t2_limit = 0xFFFF;
break;
case 0x1f801820: mdec0_write(data); break;
case 0x1f801824: mdec1_write(data); break;
default:
HW32(adr-0x1f800000)=data;
break;
}
}